﻿using System.Configuration;
using System.Globalization;
using System.Text;

namespace System.Web.UI // ใช้ Name Space นี้ เพราะหน้า ASP ส่วนใหญ่ จะเป็น UI
{
    /*brief คลาส SsMng นี้คือ Class Session Manager 
     * Target คือ ถ้าดึง Session ที่ระบุ แล้วไม่มี Key ที่ต้องการ จะให้ redirect ไปที่หน้า login
     * Key ที่เรียก เวลา Set จะจับคู่กับพอร์ต เช่น Session["EmpSeq"] จะบันทึกเป็น Session["EmpSeq80"] กรณี Host เป็นพอร์ต 80
     * Key ที่เรียก เราทำเป็น Hard ไว้ ผ่านทาง Enum ชื่อ SsUserType สามารถเรียกผ่านทาง SsUserType พิมพ์ดอท . จะมี Option ที่ใช้ได้ขึ้นมา ป้องกันการพิมพ์ผิด
     * หากต้องการเพิ่มคีย์ ให้เพิ่มในบรรทัด --> public enum SsUserType
     * 
     * วิธีใช้ 
     * - อ่าน
     * สร้าง Object SsMng เช่น SsMng ssMng = new SsMng();
     * ssMng.GetUss(SsUserType.EmpSeq); --> ได้ค่าเป็นสตริงของตัวแปร EmpSeq
     * ssMng.GetUssI(SsUserType.EmpSeq); --> ได้ค่าเป็น Int ของตัวแปร EmpSeq
     * 
     * - บันทึกคีย์ใหม่ / เซตค่าคีย์ที่มี
     * สร้าง Object SsMng เช่น SsMng ssMng = new SsMng();
     * ssMng.SetLoginSession(ค่าการล็อกอิน); // วิธีที่ 1
     * ssMng.SetUss(SsUserType.EmpSeq, 1); --> เซตค่า Session EmpSeq มีค่า = 1
     * ssMng.SetUss("projectName", "this is a book); --> เซตค่า Session projectName มีค่า = "this is a book"
     * 
     * - ล็อกเอาท์
     * ssMng.LogoutUss();
     * 
     * - ลบคีย์ที่มี
     * ssMng.SetUss("projectName", null);
     */

    public class SsMng
    {
        private const int ExpiresHour = 1;

        private const string InternalLoginUrl = "/App_UI/Forms/Login.aspx";
        //กรณี Port ไม่ใช่ 80 = เครื่อง Develop จะใช้หน้า Login ของโมดูล นั้นๆ

        private const string EssLoginUrl = "/ESS/App_UI/Forms/Login.aspx";
        // กรณีเป็น Port 80 = เครื่อง Deploy จะใช้หน้า Login กลางคือ ESS

        public int PortNumber = HttpContext.Current.Request.Url.Port; //ServerPort

        public bool IncludePortNumberInKey = false;

        public enum SsUserType
        {
            EmpSeq,
            UserName,
            UserSeq,
            WorkingJobSiteSeq,
            Height,
            UserDetail
        }

        // ถ้าต้องการเพิ่มตัวแปร Session ให้มาเพิ่มที่ตัวนี้ด้วย

        #region Get Value Zone

        public string GetUss(SsUserType ssUserType)
        // ดึงข้อมูล จาก Session ตาม Key ที่ระบุ, และย้ำลง/ขยายเวลาหมด Cookie ไปในตัว
        {
            // 1. Session ไม่มีค่า แต่ Cookie มีค่า
            HttpCookie cookieUserDetail = ReadAndExtendExpireCookie();
            HttpContext.Current.Session[KeyWithPort(SsUserType.EmpSeq)] =
                cookieUserDetail[KeyWithPort(SsUserType.EmpSeq)];
            HttpContext.Current.Session[KeyWithPort(SsUserType.UserName)] =
                cookieUserDetail[KeyWithPort(SsUserType.UserName)];
            HttpContext.Current.Session[KeyWithPort(SsUserType.UserSeq)] =
                cookieUserDetail[KeyWithPort(SsUserType.UserSeq)];
            HttpContext.Current.Session[KeyWithPort(SsUserType.WorkingJobSiteSeq)] =
                cookieUserDetail[KeyWithPort(SsUserType.WorkingJobSiteSeq)];
            HttpContext.Current.Session[KeyWithPort(SsUserType.Height)] =
                cookieUserDetail[KeyWithPort(SsUserType.Height)];

            if (HttpContext.Current.Session[KeyWithPort(ssUserType)] == null)
                throw new Exception("No session name [\"" + KeyWithPort(ssUserType) + "\"], but not redirect");

            return HttpContext.Current.Session[KeyWithPort(ssUserType)].ToString();
        }

        public int GetUssI(SsUserType ssUserType) // Get user session as int
        {
            int result;
            Int32.TryParse(GetUss(ssUserType), out result);
            return result;
        }

        // ดึง Session Value (String)
        /* ให้ง่ายต่อการใช้ สามารถดึง Value ของ Session ได้ผ่าน Properties เหล่านี้ทันที*/

        public string EmpSeq
        {
            get { return GetUss(SsUserType.EmpSeq); }
            set { SetUss(SsUserType.EmpSeq, value); }
        }

        public string UserName
        {
            get { return GetUss(SsUserType.UserName); }
            set { SetUss(SsUserType.UserName, value); }
        }

        public string UserSeq
        {
            get { return GetUss(SsUserType.UserSeq); }
            set { SetUss(SsUserType.UserSeq, value); }
        }

        public string WorkingJobSiteSeq
        {
            get { return GetUss(SsUserType.WorkingJobSiteSeq); }
            set { SetUss(SsUserType.WorkingJobSiteSeq, value); }
        }

        public string Height
        {
            get { return String.IsNullOrEmpty(GetUss(SsUserType.Height)) ? "500" : GetUss(SsUserType.Height); }
            set { SetUss(SsUserType.Height, value); }
        }

        public string UserDetail
        {
            get { return GetUss(SsUserType.UserDetail); }
            set { SetUss(SsUserType.UserDetail, value); }
        }

        // ดึง Session Value (Int) --> ถ้า Session มีค่าว่าง แปลงเป็น Int ไม่ได้ จะ Throw Error
        /* ให้ง่ายต่อการใช้ สามารถดึง Value ของ Session ได้ผ่าน Properties เหล่านี้ทันที*/

        public int EmpSeqI
        {
            get { return GetUssI(SsUserType.EmpSeq); }
            set { SetUss(SsUserType.EmpSeq, value); }
        }

        public int UserSeqI
        {
            get { return GetUssI(SsUserType.UserSeq); }
            set { SetUss(SsUserType.UserSeq, value); }
        }

        public int WorkingJobSiteSeqI
        {
            get { return GetUssI(SsUserType.WorkingJobSiteSeq); }
            set { SetUss(SsUserType.WorkingJobSiteSeq, value); }
        }

        public int HeightI
        {
            get { return GetUssI(SsUserType.Height) == 0 ? 500 : GetUssI(SsUserType.Height); }
            set { SetUss(SsUserType.Height, value); }
        }

        public bool HasUserCookie()
        {
            return HttpContext.Current.Request.Cookies[SsUserType.UserDetail.ToString()] != null;
        }

        public string ServerName
        {
            get
            {
                string port = HttpContext.Current.Request.Url.Port.ToString(CultureInfo.InvariantCulture);
                return HttpContext.Current.Request.Url.Host +
                    (port == "80" ? "" : ":" + port);
            }
        }

        public override string ToString()
        {
            StringBuilder result = new StringBuilder();
            result.Append("This is session<br>");
            foreach (var s in HttpContext.Current.Session.Keys)
            {
                result.Append(s);
                result.Append("=");
                result.Append(HttpContext.Current.Session[s.ToString()]);
                result.Append("<br>");
            }
            result.Append("<br>");
            result.Append("This is cookie<br>");
            HttpCookie ck = HttpContext.Current.Request.Cookies[SsUserType.UserDetail.ToString()];
            if (ck != null && ck.HasKeys)
            {
                foreach (var s in ck.Values)
                {
                    result.Append(s);
                    result.Append("=");
                    result.Append(ck[s.ToString()]);
                    result.Append("<br>");
                }
            }
            return result.ToString();
        }

        #endregion

        #region Set Value Zone

        public void SetLoginSession(string userSeq,
            string empSeq,
            string userName,
            string workingJobSiteSeq = "-1",
            string height = "600",
            bool includePortNumberInKey = false)
        {
            IncludePortNumberInKey = includePortNumberInKey;

            HttpCookie cookieUserDetail = HttpContext.Current.Response.Cookies[KeyWithPort(SsUserType.UserDetail)] ??
                HttpContext.Current.Response.Cookies[KeyWithPort(SsUserType.UserDetail)];

            if (cookieUserDetail == null)
                HttpContext.Current.Response.Cookies.Add(new HttpCookie(KeyWithPort(SsUserType.UserDetail)));

            // Set Session 
            HttpContext.Current.Session[KeyWithPort(SsUserType.EmpSeq)] = empSeq;
            HttpContext.Current.Session[KeyWithPort(SsUserType.UserName)] = userName;
            HttpContext.Current.Session[KeyWithPort(SsUserType.UserSeq)] = userSeq;
            HttpContext.Current.Session[KeyWithPort(SsUserType.WorkingJobSiteSeq)] = workingJobSiteSeq;
            HttpContext.Current.Session[KeyWithPort(SsUserType.Height)] = height;

            // Set Cookie 
            // Remark : now if cookieUserDetail == null , meaning Can't create cookie
            if (cookieUserDetail != null)
            {
                HttpContext.Current.Session[KeyWithPort(SsUserType.EmpSeq)] =
                    cookieUserDetail[KeyWithPort(SsUserType.EmpSeq)] = empSeq;
                HttpContext.Current.Session[KeyWithPort(SsUserType.UserName)] =
                    cookieUserDetail[KeyWithPort(SsUserType.UserName)] = userName;
                HttpContext.Current.Session[KeyWithPort(SsUserType.UserSeq)] =
                    cookieUserDetail[KeyWithPort(SsUserType.UserSeq)] = userSeq;
                HttpContext.Current.Session[KeyWithPort(SsUserType.WorkingJobSiteSeq)] =
                    cookieUserDetail[KeyWithPort(SsUserType.WorkingJobSiteSeq)] = workingJobSiteSeq;
                HttpContext.Current.Session[KeyWithPort(SsUserType.Height)] =
                    cookieUserDetail[KeyWithPort(SsUserType.Height)] = height;
            }
        }

        public void SetUss(string key, int value)
        {
            SetUss(key, Convert.ToString(value));
        }

        public void SetUss(string key, string value)
        {
            HttpCookie cookieUserDetail = HttpContext.Current.Response.Cookies[KeyWithPort(SsUserType.UserDetail)];

            if (cookieUserDetail == null)
                HttpContext.Current.Response.Cookies.Add(new HttpCookie(KeyWithPort(SsUserType.UserDetail)));

            HttpContext.Current.Session[KeyWithPort(key)] = cookieUserDetail[KeyWithPort(key)] = value;

        }

        public void SetUss(SsUserType ssUserType, int value)
        {
            SetUss(ssUserType, Convert.ToString(value));
        }

        public void SetUss(SsUserType ssUserType, string value)
        {
            HttpCookie cookieUserDetail = HttpContext.Current.Response.Cookies[KeyWithPort(SsUserType.UserDetail)];

            if (cookieUserDetail == null)
                HttpContext.Current.Response.Cookies.Add(new HttpCookie(KeyWithPort(SsUserType.UserDetail)));

            HttpContext.Current.Session[KeyWithPort(SsUserType.EmpSeq)] =
                cookieUserDetail[KeyWithPort(SsUserType.EmpSeq)] = value;
        }

        #endregion

        #region Delete Zone

        public void DeleteUss(string key)
        {
            HttpCookie cookieUserDetail = HttpContext.Current.Response.Cookies[KeyWithPort(SsUserType.UserDetail)];

            if (cookieUserDetail == null)
                HttpContext.Current.Response.Cookies.Add(new HttpCookie(KeyWithPort(SsUserType.UserDetail)));

            HttpContext.Current.Session.Remove(KeyWithPort(SsUserType.EmpSeq));
            // remark : data still in cookie.
        }

        public void LogoutUss()
        {
            HttpCookie cookie = ReadAndExtendExpireCookie();

            if (cookie != null)
            {
                cookie.Expires = DateTime.Now.AddDays(-1);
            }

            // RadMenu1.Items.Clear();
            HttpContext.Current.Session.Abandon();
            HttpContext.Current.Response.Redirect("//" + GetServerString() + "/ESS/APP_UI/Forms/Login.aspx");
        }

        #endregion

        #region Miscellenous

        public void CheckUss() // If not found, GetUss() also do work Redirect to login page
        {
            GetUss(SsUserType.UserName);
        }

        public string GetServerString()
        {
            return HttpContext.Current.Request.Url.Host +
                       (ConfigurationSettings.AppSettings["SubSystem"].Length > 0
                            ? "/" + ConfigurationSettings.AppSettings["SubSystem"]
                            : "") +
                        "/";

        }

        private string KeyWithPort(SsUserType ssUserType)
        {
            string port = IncludePortNumberInKey ? PortNumber.ToString(CultureInfo.InvariantCulture) : String.Empty;
            return String.Format("{0}{1}", ssUserType, port);
        }

        private string KeyWithPort(string key)
        {
            string port = IncludePortNumberInKey ? PortNumber.ToString(CultureInfo.InvariantCulture) : String.Empty;
            return String.Format("{0}{1}", key, port);
        }

        /* breif Method ย้ำไปย้ำมา */
        public HttpCookie ReadAndExtendExpireCookie()
        {
            // โหลด Cookie
            HttpCookie cookieUserDetail = HttpContext.Current.Response.Cookies[KeyWithPort(SsUserType.UserDetail)];

            // ถ้า Cookie ไม่ได้ถูกเซต, noCookie = true
            bool noCookie = cookieUserDetail == null || !cookieUserDetail.HasKeys;
            // ถ้า Session ไม่ได้ถูกเซต , noSession = true
            bool noSession = HttpContext.Current.Session[KeyWithPort(SsUserType.UserSeq)] == null ||
                             (string)HttpContext.Current.Session[KeyWithPort(SsUserType.UserSeq)] == "";

            // ประมวลผล #1 : ถ้า Cookie ไม่ได้ถูกเซต Session ไม่ได้ถูกเซต แสดงว่าไม่ได้ Login แน่นอน, ทำการ Redirect ไปหน้า Login
            if (noCookie && noSession)
            {
                HttpContext.Current.Response.Redirect(PortNumber == 80 ? EssLoginUrl : InternalLoginUrl);
            }

            // ถ้า Session ไม่ได้ถูกเซต ให้ลองโหลดจาก Cookie
            if (noSession)
            {
                HttpContext.Current.Session[KeyWithPort(SsUserType.EmpSeq)] =
                    cookieUserDetail[KeyWithPort(SsUserType.EmpSeq)];
                HttpContext.Current.Session[KeyWithPort(SsUserType.UserName)] =
                    cookieUserDetail[KeyWithPort(SsUserType.UserName)];
                HttpContext.Current.Session[KeyWithPort(SsUserType.UserSeq)] =
                    cookieUserDetail[KeyWithPort(SsUserType.UserSeq)];
                HttpContext.Current.Session[KeyWithPort(SsUserType.WorkingJobSiteSeq)] =
                    cookieUserDetail[KeyWithPort(SsUserType.WorkingJobSiteSeq)];
                HttpContext.Current.Session[KeyWithPort(SsUserType.Height)] =
                    cookieUserDetail[KeyWithPort(SsUserType.Height)];
            }

            // สร้าง Cookie กรณีที่  Session มีค่า แต่ Cookie ไม่ได้สร้าง
            if (HttpContext.Current.Response.Cookies[KeyWithPort(SsUserType.UserDetail)] == null)
                HttpContext.Current.Response.Cookies.Add(new HttpCookie(KeyWithPort(SsUserType.UserDetail)));

            // สร้าง Cookie ไม่ได้ อาจเป็นเรื่อง Security ในบราวเซอร์ไม่ยอม, ให้จบการทำงานในฟังก์ชั่น เพราะหลังจากนี้เป็นการ Set Cookie
            if (cookieUserDetail == null)
                return null;

            // Set ค่าตาม Parameter
            cookieUserDetail[KeyWithPort(SsUserType.EmpSeq)] =
                (string)HttpContext.Current.Session[KeyWithPort(SsUserType.EmpSeq)];
            cookieUserDetail[KeyWithPort(SsUserType.UserName)] =
                (string)HttpContext.Current.Session[KeyWithPort(SsUserType.UserName)];
            cookieUserDetail[KeyWithPort(SsUserType.UserSeq)] =
                (string)HttpContext.Current.Session[KeyWithPort(SsUserType.UserSeq)];
            cookieUserDetail[KeyWithPort(SsUserType.WorkingJobSiteSeq)] =
                (string)HttpContext.Current.Session[KeyWithPort(SsUserType.WorkingJobSiteSeq)];
            cookieUserDetail[KeyWithPort(SsUserType.Height)] =
                (string)HttpContext.Current.Session[KeyWithPort(SsUserType.Height)];

            // ตั้งเวลาหมดอายุ 1 ชั่วโมง หลังจากการเรียก Method ครั้งนี้
            cookieUserDetail.Expires = DateTime.Now.AddHours(ExpiresHour);

            // Return Cookie ตัวนี้
            return cookieUserDetail;
        }

        #endregion
    }
}